//
//  RotationGestureView.m
//  AloneInTheLight
//
//  Created by Michael Sherron on 10/4/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "RotationGestureView.h"

#define DEGREES_TO_RADIANS(x) (x / 180.0f * (long double)M_PI)
#define kNormal 15
#define kTargetVelocity 0.35
#define kTimeRequirement 3

@implementation RotationGestureView

@synthesize origin;
@synthesize startPoint;
@synthesize lastValidTheta;
@synthesize lastValueWasZero;
@synthesize totalCircles, partialCircles;
@synthesize velocity;
@synthesize conversionToSeconds;
@synthesize previousTime;
@synthesize previousTheta;
@synthesize soundController;
@synthesize finalAverageVelocity;
@synthesize shard;
@synthesize parent;
@synthesize rotatingCircle;
@synthesize circleImage;
@synthesize rotationAnimation;
@synthesize isSinging; // Can't I just make a variable without property?
@synthesize rotationHidden;

- (void)dealloc
{
    [rotatingCircle release];
    [soundController release];
    
    [super dealloc];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        
        origin = CGPointMake(frame.size.width / 2, frame.size.height / 2);
        
        [self calculateTickToSecondsRatio];
        
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

- (void)setupSoundAndCircle
{
    circleImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    circleImage.image = [UIImage imageNamed:@"Circle.png"];
    [self addSubview:circleImage];
    self.rotatingCircle = circleImage;
    
    CATransform3D rotationTransform = CATransform3DMakeRotation(1.0f * M_PI, 0, 0, 1.0);
    
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    
    rotationAnimation.toValue = [NSValue valueWithCATransform3D:rotationTransform];
    rotationAnimation.duration = 1.00f;
    rotationAnimation.cumulative = YES;
    rotationAnimation.repeatCount = 450; 
    
    [circleImage.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
    
    [circleImage release];
    
    //soundController = [[SoundController alloc] init];
    isSinging = NO;
}

- (void)hideRotationGesture
{
    [soundController stopSinging];
    isSinging = NO;
    rotationHidden = YES;
    self.alpha = 0;
    //[self removeFromSuperview];
}

- (BOOL)isHidden
{
    return rotationHidden;
}

- (void)revealRotationGesture
{
    rotationHidden = NO;
    rotatingCircle.alpha = 1;
}

- (void)calculateTickToSecondsRatio
//this method is used to calculate the "tick to seconds" ratio.
//this ratio is CPU and Bus dependant; this should help make the game compatible with not only the iPad 2, but the original iPad and any future iPads
{
    static NSInteger tryNumber = 0;
    tryNumber++;    //keep track of the number of tries.  In theory, it should never have to try more than once... but I'm not sure how "mach_timebase_info" acutally works
    
    NSLog(@"Attempting to calculate conversionToSeconds ratio... Try #%d", tryNumber);
    
    mach_timebase_info_data_t info;
    kern_return_t err = mach_timebase_info( &info );
    
	//Convert the timebase into seconds
    if(err == 0) conversionToSeconds = 1e-9 * (double) info.numer / (double) info.denom;
    else [self calculateTickToSecondsRatio];   //bad coding because there is the possibility of an infinite loop... on the other hand though, the game can't run properly
    //anyway if the conversionToSeconds ratio isn't calculated.  We'll deal with this later if it becomes an issue
}



- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (rotationHidden)
        return;
    
    NSLog(@"touches beagain");
    
    UITouch *touch = [touches anyObject];
    
    previousTime = mach_absolute_time();
    
    finalAverageVelocity = 0;
    velocity = 0;
    previousTheta = 0;
    lastValidTheta = 0;
    totalCircles = 0;
    partialCircles = 0;
    lastValueWasZero = YES;
    
    startPoint = [touch locationInView:self];
    //startPoint = CGPointMake(startPoint.x - origin.x, startPoint.y - origin.y);
    

    //[soundController startSinging];
}


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (rotationHidden)
        return;
    
    if (!isSinging) {
        [soundController startSinging];
        isSinging = YES;
    }
    //NSLog(@"touches moved");
    
    static long double normal = 0;
    static long double averageVelocity = 0;
    
    UITouch *touch = [touches anyObject];
    
    CGPoint nextPoint = [touch locationInView:self];
    //nextPoint = CGPointMake(nextPoint.x - origin.x, nextPoint.y - origin.y);
    
    double p12 = [self getDistance: startPoint andPoint: origin];
    //p12 = p12 * p12;
    
    double p13 = [self getDistance: nextPoint andPoint: origin];
    //p13 = p13 * p13;
    
    double p23 = [self getDistance: startPoint andPoint: nextPoint];
    
    double theta = acosf(((p12*p12) + (p13*p13) - (p23*p23))/(2*p12*p13));
    
    /*
    long double dotProduct = nextPoint.x * startPoint.x + nextPoint.y * startPoint.y;
    //NSLog(@"dotProduct = %Lf", dotProduct);
    long double magnitudeProduct = sqrtl(nextPoint.x * nextPoint.x + nextPoint.y * nextPoint.y) * sqrtl(startPoint.x * startPoint.x + startPoint.y + startPoint.y);
    //NSLog(@"magenitudeProduct = %Lf", magnitudeProduct);
    long double theta = acosf(dotProduct / magnitudeProduct);
    
    if(!isnan(theta))
    {
        lastValidTheta = theta;
        partialCircles = M_PI / theta;
    }
    else
    {
        if(lastValidTheta > M_PI / 2) theta = M_PI;
        else theta = 0;
        
        partialCircles = 0;
        if((theta == 0 && lastValueWasZero == NO) || (theta == M_PI && lastValueWasZero == YES))
        {
            lastValueWasZero = !lastValueWasZero;
            
            //startPoint = nextPoint;
        }
    }
    
    if(!lastValueWasZero)
    {
        theta = 2 * M_PI - theta;
    }
    */
    //NSLog(@"lastValueWasZero %d", lastValueWasZero);
    
    //NSLog(@"theta = %Lf", theta);
        
    uint64_t newTime = mach_absolute_time();
    uint64_t changeInTime = newTime - previousTime;
    long double changeInTheta =  theta - previousTheta;
    if(changeInTheta < 0) changeInTheta = changeInTheta * -1;
    if(changeInTheta != 0)
    {
        velocity = (changeInTheta / (2 * M_PI)) / (changeInTime * conversionToSeconds); 

        averageVelocity += velocity;
        normal++;

        if(normal > kNormal)
        {
            long double tempFinalVeloc = averageVelocity / normal;
            
            if (!(tempFinalVeloc + .20 > finalAverageVelocity && tempFinalVeloc - .20 < finalAverageVelocity))
            {
                finalAverageVelocity = tempFinalVeloc;
            }
            
            normal = 0;
            averageVelocity = 0;
            //NSLog(@"finalAverageVelocity = %Lf", finalAverageVelocity);

        }

        [soundController setSingPitch: finalAverageVelocity * 2];
        
        // Stop sounds if player stops moving finger
        // Might be glitchy
        if (velocity < .3) {
            [soundController stopSinging];
            isSinging = NO;
        }
        
    }
    
    [soundController updateSingPitch];
    previousTime = newTime;
    previousTheta = theta;
    
    static BOOL getStartTime = YES;
    if(finalAverageVelocity < kTargetVelocity + .2 && finalAverageVelocity > kTargetVelocity - .2)
    {
        static uint64_t startTime;
        static BOOL flash = YES;
        
        if(flash)
        {
            flash = NO;
            shard.alpha = .1;
        }
        else
        {
            flash = YES;
            shard.alpha = 1;
        }
        
        if(getStartTime)
        { 
            startTime = mach_absolute_time(); 
            startTime = startTime * conversionToSeconds; 
            getStartTime = NO; 
        }
        
        uint64_t currentTime = mach_absolute_time() * conversionToSeconds;
        
        if(currentTime - startTime > kTimeRequirement)
        {
            NSLog(@"You win!");
            
            shard.alpha = 1;
            [UIView animateWithDuration:1.5 animations:^
            {
                shard.transform = CGAffineTransformMakeTranslation(0, -1000);
                rotatingCircle.alpha = 0;
            }
            completion:^(BOOL finished)
            {
                [parent toggleGesturesOn];
                [soundController stopSinging];
                [self removeFromSuperview];
            }];
        }
    }
    else
    {
        getStartTime = YES;
        shard.alpha = 1;
    }
}

- (double)getDistance: (CGPoint)to andPoint: (CGPoint) from
{
    return sqrt(((to.x - from.x)*(to.x - from.x)) + ((to.y - from.y)*(to.y-from.y)));
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (rotationHidden)
        return;
    
    [soundController stopSinging];
    isSinging = NO;
    NSLog(@"touches ended");
    
    shard.alpha = 1;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touches cancelled");
}



/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/

@end
